package com.jk.vehicle.mini.controller;

import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jk.vehicle.mini.components.WxService;
import com.jk.vehicle.mini.config.MineConfig;
import com.jk.vehicle.mini.constant.UserTypeEnum;
import com.jk.vehicle.mini.dto.UserSignUpDTO;
import com.jk.vehicle.mini.entity.*;
import com.jk.vehicle.mini.service.*;
import com.jk.vehicle.mini.util.AESUtils;
import com.jk.vehicle.mini.util.BeanMapperUtil;
import com.jk.vehicle.mini.util.RedisUtil;
import com.jk.vehicle.mini.util.SequenceUtils;
import com.jk.vehicle.mini.vo.BicycleLinkIdVO;
import com.jk.vehicle.core.controller.BaseController;
import com.jk.vehicle.core.entity.ResponseEntity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import tk.mybatis.mapper.entity.Condition;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import javax.validation.Valid;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * 登陆注册相关
 */
@Api(value = "登陆注册相关接口", tags = "登陆注册相关接口")
@Slf4j
@RestController
@RequestMapping("/sign")
public class SignController extends BaseController {
    @Resource
    private UserService userService;

    @Resource
    private WxService wxService;

    @Resource
    private UserBicycleLinkService userBicycleLinkService;

    @Resource
    private ElectricBicycleService electricBicycleService;

    @Resource
    private UserLoginRecordService userLoginRecordService;

    @Resource
    private CorpService corpService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private MineConfig mineConfig;

    /**
     * redis保存sessionKey时使用的后缀
     */
    private final static String SESSION_KEY_SUFFIX = "_session_key";

    /**
     * 登陆接口√
     * @param code
     * @return
     */
    @ApiOperation("登陆接口")
    @GetMapping("/sign_in")
    @ApiImplicitParams({
        @ApiImplicitParam(name = "code", value = "前端获取小程序的登陆code")
    })
    public ResponseEntity<User> signIn(String code){
        String result = wxService.loginApplets(code, mineConfig.getWxAppId(), mineConfig.getWxSecret());
        if (StringUtils.isBlank(result)){
            return failResult("登陆出现异常，调用微信api登录返回为空！");
        }
        JSONObject wxObject = JSONObject.parseObject(result);
        if(wxObject.containsKey("errcode") && wxObject.getInteger("errcode") != 0){
            return failResult(wxObject.getString("errmsg"));
        }
        // 获取微信用户得openId
        String openId = wxObject.getString("openid");
        // 获取微信用户的sessionKey，并保存到缓存
        String sessionKey = wxObject.getString("session_key");
        redisUtil.set(openId + SESSION_KEY_SUFFIX, sessionKey);
        Condition condition = new Condition(User.class);
        condition.createCriteria().andEqualTo("wxId", openId);
        User user = null;
        List<User> userList = userService.findByCondition(condition, null);
        if (userList.isEmpty()){
            user = User.UserBuilder.anUser().withWxId(openId).build();
            return new ResponseEntity().setCode(HttpStatus.FORBIDDEN.value()).setData(user);
        } else {
            user = userList.get(0);
            // 当前用户绑定车辆之后才能插入登录记录
            List<String> dsNameList = new ArrayList<>();
            List<UserBicycleLink> userBicycleLinkList = userBicycleLinkService.queryUserBicycleLinkCorpById(user.getId());
            if (!CollectionUtils.isEmpty(userBicycleLinkList)) {
                for (UserBicycleLink userBicycleLink: userBicycleLinkList) {
                    String dsName = corpService.selectDsNameById(userBicycleLink.getCorpId());
                    dsNameList.add(null);// null：代表通用数据源，非空代表独立数据源
                    dsNameList.add(dsName);
                }
            }
            if (!CollectionUtils.isEmpty(userBicycleLinkList)) {
                for (String dsName: dsNameList) {
                    condition = new Condition(UserLoginRecord.class);
                    condition.createCriteria().andEqualTo("userId", user.getId());
                    condition.createCriteria().andCondition("date_format(create_date, '%Y-%m-%d') = date_format(now(),'%Y-%m-%d')");
                    Integer count = userLoginRecordService.countByCondition(condition, null);
                    if (count < 1) {
                        UserLoginRecord userLoginRecord = new UserLoginRecord();
                        userLoginRecord.setId(SequenceUtils.nextId());
                        userLoginRecord.setUserId(user.getId());
                        userLoginRecord.setCreateDate(new Date());
                        userLoginRecordService.save(userLoginRecord, dsName);
                    }
                }
            }
        }
        return successResult(user);
    }

    @ApiOperation(value = "注册接口")
    @PostMapping(value = {"/register"})
    @ApiImplicitParams({
            @ApiImplicitParam(name = "",value = "",readOnly = true),
            @ApiImplicitParam(name = "",value = "",readOnly = true)
    })
    public ResponseEntity<User> sign_in(){



        return successResult();
    }


    /**
     * 注册接口√
     * @param userSignUpDTO
     * @param bindingResult
     * @return
     */
    @ApiOperation(value = "注册接口")
    @PostMapping
    public ResponseEntity<User> signUp(@Valid @RequestBody UserSignUpDTO userSignUpDTO, BindingResult bindingResult){
        checkBindingResult(bindingResult);
        String wxId = userSignUpDTO.getWxId();
        Condition condition = new Condition(User.class);
        Example.Criteria criteria = condition.createCriteria();
        criteria.andEqualTo("wxId", wxId);
        List<User> userList = userService.findByCondition(condition, null);
        // 如果根据微信id找不到用户，则进行新增操作，否则返回用户数据。
        User user;
        System.out.println("登录接口");
        if (userList.isEmpty()){
            user = new User();
            // 进行用户新增操作
            BeanMapperUtil.convert(userSignUpDTO, user);
            // 雪花算法生成ID
            user.setId(SequenceUtils.nextId());
            user.setCreateDate(new Date());
            // 新增用户
            userService.save(user, null);
            return successResult(user);
        } else {
            return failResult("注册有误，人员已经在系统中存在");
        }
    }

    /**
     * 解密微信用户手机号√
     * @param encryptedData
     * @param iv
     * @param openId
     * @return
     */
    @ApiOperation("解密微信用户手机号")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "encryptedData", value = "包括敏感数据在内的完整用户信息的加密数据"),
            @ApiImplicitParam(name = "iv", value = "加密算法的初始向量"),
            @ApiImplicitParam(name = "openId", value = "用户小程序openId")
    })
    @GetMapping("/decode_wx_user_pn")
    public ResponseEntity<String> decodeWxUserPN(String encryptedData, String iv, String openId){
        if (StringUtils.isBlank(encryptedData) || StringUtils.isBlank(iv) || StringUtils.isBlank(openId)){
            return failResult("缺失必要参数！");
        }
        if (redisUtil.get(openId + SESSION_KEY_SUFFIX) == null){
            return failResult("当前用户对应的sessionKey不存在！");
        }
        //AESUtils微信获取手机号解密工具类
        String sessionKey = redisUtil.get(openId + SESSION_KEY_SUFFIX) == null ? "" : redisUtil.get(openId + SESSION_KEY_SUFFIX).toString();
        //调用AESUtils工具类decrypt方法解密获取json串
        byte[] resultByte;
        try{
            resultByte = AESUtils.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
        }catch (Exception e){
            log.error("解密微信敏感数据时报错：{}", e.getMessage());
            return failResult("解密微信敏感数据时出错！");
        }
        //判断返回参数是否为空
        if (null != resultByte && resultByte.length > 0) {
            String jsons = new String(resultByte, StandardCharsets.UTF_8);
            JSONObject json = JSON.parseObject(jsons);
            //json解析phoneNumber值
            String phoneNumber = json.getString("phoneNumber");
            return successResult(phoneNumber);
        }
        return failResult("密文解析失败，解密后数组为空！");
    }
}
